#include "codesvrctrl.h"

#define CONVERTUP1(MsgID, ClassNameReq, ClassNameAns) \
    case MsgID: \
        if (m_stDataHead.shMsgType == EMT_REQUEST) \
        { \
            ConvertUp<ClassNameReq>(#ClassNameReq); \
        } \
        else if (m_stDataHead.shMsgType == EMT_ANSWER) \
        { \
            ConvertUp<ClassNameAns>(#ClassNameAns); \
        } \
        else \
        { \
            CT_WARNING(("this msg do not allow that Type MsgHead data: Msg=%d Type=%d Act=%lld", \
                m_stDataHead.shMsgID, m_stDataHead.shMsgType, m_stDataHead.shMsgType, m_stDataHead.llMsgAct)); \
            return -2; \
        } \
        break

#define CONVERTUP2(MsgID, ClassNameNotify) \
    case MsgID: \
        if (m_stDataHead.shMsgType == EMT_NOTIFY) \
        { \
            ConvertUp<ClassNameNotify>(#ClassNameNotify); \
        } \
        else \
        { \
            CT_WARNING(("this msg do not allow that Type MsgHead data: Msg=%d Type=%d Act=%lld", \
                m_stDataHead.shMsgID, m_stDataHead.shMsgType, m_stDataHead.shMsgType, m_stDataHead.llMsgAct)); \
            return -2; \
        } \
        break

#define CONVERTDOWN1(MsgID, ClassNameReq, ClassNameAns) \
    case MsgID: \
        if (m_stDataHead.shMsgType == EMT_REQUEST) \
        { \
            ConvertDown<ClassNameReq>(#ClassNameReq); \
        } \
        else if (m_stDataHead.shMsgType == EMT_ANSWER) \
        { \
            ConvertDown<ClassNameAns>(#ClassNameAns); \
        } \
        else \
        { \
            CT_WARNING(("this msg do not allow that Type MsgHead data: Msg=%d Type=%d Act=%lld", \
                m_stDataHead.shMsgID, m_stDataHead.shMsgType, m_stDataHead.shMsgType, m_stDataHead.llMsgAct)); \
            return -2; \
        } \
        break

#define CONVERTDOWN2(MsgID, ClassNameNotify) \
    case MsgID: \
        if (m_stDataHead.shMsgType == EMT_NOTIFY) \
        { \
            ConvertDown<ClassNameNotify>(#ClassNameNotify); \
        } \
        else \
        { \
            CT_WARNING(("this msg do not allow that Type MsgHead data: Msg=%d Type=%d Act=%lld", \
                m_stDataHead.shMsgID, m_stDataHead.shMsgType, m_stDataHead.shMsgType, m_stDataHead.llMsgAct)); \
            return -2; \
        } \
        break

bool CCodeSvrCtrl::s_bExit = false;
bool CCodeSvrCtrl::s_bReloadConfig = false;

CCodeSvrCtrl::CCodeSvrCtrl(void)
{
}

CCodeSvrCtrl::~CCodeSvrCtrl(void)
{
}

void CCodeSvrCtrl::Init(void)
{
	// 安装信号处理函数
	signal(SIGUSR1, CCodeSvrCtrl::sigusr1_handle);	// kill -USR1 pid 会让程序安全的退出
    signal(SIGUSR2, CCodeSvrCtrl::sigusr2_handle);	// kill -USR2 pid 会让程序安全的退出
	 
    // 读取配置
	CONF->LoadConfig();
 
    int iRet = 0;
    iRet = m_stEpoll.Init(EPOLL_SIZE, EPOLL_WAIT_SIZE);
    CHECK_THROW(iRet);

    CT_INFO(("Init EnpShm Key = %s",CONF->EnpStreamKey));
    // 初始化和enpsvr通讯的共享内存管道
    iRet = m_stEnpShm.Init(true,
        CONF->EnpStreamKey ,
        CONF->EnpStreamSize ,
        CONF->EnpFrontEndSocket,
        CONF->EnpBackEndSocket,
        m_stEpoll,
        *this,
        &CCodeSvrCtrl::OnEnpQueueEvent);
    CHECK_THROW(iRet);

    // 初始化和mainsvr通讯的共享内存管道
    iRet = m_stMainShm.Init(false,
        CONF->MainStreamKey,
        CONF->MainStreamSize,
        CONF->MainFrontEndSocket,
        CONF->MainBackEndSocket,
        m_stEpoll,
        *this,
        &CCodeSvrCtrl::OnMainQueueEvent);
    CHECK_THROW(iRet);
    ZREOBUFF(m_stEnpBuffOut);
    ZREOBUFF(m_stMainBuffOut);

    m_stEnpIn.Attach(m_stEnpBuffIn.streamBuffs, (unsigned short)STREAM_BUFF_LENGTH);
    m_stEnpOut.Attach(m_stEnpBuffOut.streamBuffs, (unsigned short)STREAM_BUFF_LENGTH);
    m_stMainIn.Attach(m_stMainBuffIn.streamBuffs, (unsigned short)STREAM_BUFF_LENGTH);
    m_stMainOut.Attach(m_stMainBuffOut.streamBuffs, (unsigned short)STREAM_BUFF_LENGTH);
    m_stDecrypt.Attach(m_stDecryptBuf.streamBuffs, (unsigned short)STREAM_BUFF_LENGTH);
    m_stStrToHex.Attach(m_stStrToHexBuf.streamBuffs, (unsigned short)STREAM_BUFF_LENGTH);
	
	CT_INFO(("codesvr init ok"));
}

void CCodeSvrCtrl::Run(void)
{
	while (true)
	{
	   if (s_bReloadConfig)
		{
			CT_INFO(("recv signal, codesvr reload config"));
			s_bReloadConfig = false;
			CONF->ReloadConfig();
		}

		if (s_bExit)
		{
			CT_INFO(("codesvr exit"));
			s_bExit = false;
			return;
		}

		m_stEpoll.WaitAndEvent(_DEF_SLEEP_TIMER);
		Poll();
	}
}

void CCodeSvrCtrl::Exit(void)
{
	CT_INFO(("codesvr exit"));
}

void CCodeSvrCtrl::sigusr1_handle(int iSigVal)
{
	s_bReloadConfig = true;
	signal(SIGUSR1, CCodeSvrCtrl::sigusr1_handle);
}

void CCodeSvrCtrl::sigusr2_handle(int iSigVal)
{
    s_bExit = true;
    signal(SIGUSR2, CCodeSvrCtrl::sigusr2_handle);
}

void CCodeSvrCtrl::OnEnpQueueEvent(CodeNetEpollObject* pstObject, SOCKET iSocket, int iEvent)
{
    CT_TRACE(("OnEnpQueueEvent socket=%d event=%d", iSocket, iEvent));
    m_stEnpShm.ClearNotify();
}

void CCodeSvrCtrl::OnMainQueueEvent(CodeNetEpollObject* pstObject, SOCKET iSocket, int iEvent)
{
    CT_TRACE(("OnMainQueueEvent socket=%d event=%d", iSocket, iEvent));
    m_stMainShm.ClearNotify();
}

void CCodeSvrCtrl::Push(void)
{
    int iRet = 0;
    if (m_stEnpBuffOut._offset)
    {
        iRet = m_stEnpShm.PutOneCode(m_stEnpBuffOut.streamBuffs, m_stEnpBuffOut._offset);
        if (iRet)
        {
            CT_WARNING(("put onecode to enp error"));
        }
        else
        {
            CT_TRACE(("put onecode to enp ok, len = %d", m_stEnpBuffOut._offset));
        }
        
        ZREOBUFF(m_stEnpBuffOut);
    }

    if (m_stMainBuffOut._offset)
    {
        iRet = m_stMainShm.PutOneCode(m_stMainBuffOut.streamBuffs, m_stMainBuffOut._offset);
        if (iRet)
        {
            CT_WARNING(("put onecode to main error"));
        }
        else
        {
            CT_TRACE(("put onecode to main ok, len = %d", m_stMainBuffOut._offset));
        }
        ZREOBUFF(m_stMainBuffOut);
    }
}

int CCodeSvrCtrl::Pull(void)
{
    ZREOBUFF(m_stEnpBuffIn);
    int iRet = m_stEnpShm.GetOneCode(m_stEnpBuffIn.streamBuffs, STREAM_BUFF_LENGTH, m_stEnpBuffIn._offset);
    if (iRet != 0)
    {
        CT_WARNING(("codesvr Pull data err ShmQueue=%s failed=%d", "EnpShm", iRet));
    }

    ZREOBUFF(m_stMainBuffIn);
    iRet = m_stMainShm.GetOneCode(m_stMainBuffIn.streamBuffs, STREAM_BUFF_LENGTH, m_stMainBuffIn._offset);
    if (iRet != 0)
    {
        CT_WARNING(("codesvr Pull data err ShmQueue=%s failed=%d", "MainShm", iRet));
    }

    return m_stEnpBuffIn._offset + m_stMainBuffIn._offset;
}

int CCodeSvrCtrl::Poll()
{
    while (Pull())
    {
        m_stEnpIn.InitConvert();
        m_stEnpOut.InitConvert();
        m_stMainIn.InitConvert();
        m_stMainOut.InitConvert();
        if (m_stEnpBuffIn._offset)
        {
            ConvertDataUp();
        }

        if (m_stMainBuffIn._offset)
        {
            ConvertDataDown();
        }
  
        Push();
    }
    return 0;
}

int CCodeSvrCtrl::ConvertDataUp(void)
{
    // 读取数据头部
    if ((unsigned int)m_stEnpBuffIn._offset < sizeof(CEnpNetHead))
    {      
        CT_WARNING(("%s : data less than enphead this package reject by get enphead","EnpStreamIn"));
        return -1;
    }

    memcpy(&m_stEnphead, m_stEnpBuffIn.streamBuffs, sizeof(CEnpNetHead));
    m_stEnpIn.m_ushPos += sizeof(CEnpNetHead);
   
    if (m_stEnphead.unDataLength == 0)  //连接被关闭，直接发送到上层
    {
        memcpy(m_stMainBuffOut.streamBuffs, &m_stEnphead, sizeof(CEnpNetHead));
        m_stMainBuffOut._offset = sizeof(CEnpNetHead);
        CT_TRACE(("notify disconnect to main"));
        return 0;
    }
    
    switch (m_stEnphead.ucDeodeMethod)
    {
    case CODE_STRING :
        CodeConvert(m_stEnpIn, m_stDataHead, "CTMsgHead", string_decode());
    	break;
    case CODE_BIN :
        CodeConvert(m_stEnpIn, m_stDataHead, "CTMsgHead", bin_decode());
        break;
    default:
        return -1;
    }
    
    if (m_stEnpIn.m_iRet != 0)
    {
        // 解码错误写入日志
        CT_WARNING(("codesvr decode data head err iRet=%d", m_stEnpIn.m_iRet));
        CT_TRACE(("buffdata :"));
        CT_TRACEBINARY((m_stEnpBuffIn.streamBuffs, m_stEnpBuffIn._offset));
        return -1;
    }

    if(FindTypeAndConvertUp() != 0)
    {
        ZREOBUFF(m_stMainBuffOut);
        return -1;
    }
    else
    {
        CT_TRACE(("convert up succeed MsgID=%d MsgType=%d",
            m_stDataHead.shMsgID, m_stDataHead.shMsgType));
        return 0;
    }
}

int CCodeSvrCtrl::ConvertDataDown(void)
{
    if ((unsigned int)m_stMainBuffIn._offset <= sizeof(CEnpNetHead))
    {
        CT_WARNING(("MainSeverIn: data less than enphead this package reject by get enphead"));
        return -1;
    }

    memcpy(&m_stEnphead, m_stMainBuffIn.streamBuffs, sizeof(CEnpNetHead));
    m_stMainIn.m_ushPos = sizeof(CEnpNetHead);
    CodeConvert(m_stMainIn, m_stDataHead, "CTMsgHead", bin_decode());
    if (m_stMainIn.m_iRet != 0)
    {
        CT_WARNING(("codesvr bin decode data head err iRet=%d", m_stMainIn.m_iRet));
        CT_TRACE(("buffdata :"));
        CT_TRACEBINARY((m_stMainBuffIn.streamBuffs, m_stMainBuffIn._offset));
        return -1;
    }

    // 判断返回值情况来，如果不为零则
    if (FindTypeAndConvertDown() != 0)
    {
        ZREOBUFF(m_stEnpBuffOut);
        return -1;
    }
    else
    {
        CT_TRACE(("convert down succeed MsgID=%d MsgType=%d, bl=%d, ct=%d",
            m_stDataHead.shMsgID, m_stDataHead.shMsgType, m_stEnpBuffOut._offset, m_stEnphead.ucEnodeMethod));
        return 0;
    }
}

int CCodeSvrCtrl::FindTypeAndConvertUp()
{
    int iRet = 0;
    switch(m_stDataHead.shMsgID)
    {
        CONVERTUP1(ID_MAIN_HEART_BEAT, CReqHeartBeatMsg, CAnsHeartBeatMsg);
        CONVERTUP1(ID_MAIN_SAVE_MAP, CReqSaveMapMsg, CAnsSaveMapMsg);
        CONVERTUP1(ID_MAIN_GET_MAP, CReqGetMapMsg, CAnsGetMapMsg);
        CONVERTUP1(ID_MAIN_CREATE_GAME, CReqCreateGameMsg, CAnsCreateGameMsg);
        CONVERTUP1(ID_MAIN_FIND_PATH, CReqFindPathMsg, CAnsFindPathMsg);
        CONVERTUP1(ID_MAIN_SHOOT, CReqShootMsg, CAnsShootMsg);
        
    default:
        //插入一条警告信息
        CT_WARNING(("convert up no data body matching MsgID=%d MsgType=%d", 
            m_stDataHead.shMsgID, m_stDataHead.shMsgType));
        break;
    }

    return iRet;
}

int CCodeSvrCtrl::FindTypeAndConvertDown(void)
{
    switch (m_stDataHead.shMsgID)
    {
        CONVERTDOWN1(ID_MAIN_HEART_BEAT, CReqHeartBeatMsg, CAnsHeartBeatMsg);
        CONVERTDOWN1(ID_MAIN_SAVE_MAP, CReqSaveMapMsg, CAnsSaveMapMsg);
        CONVERTDOWN1(ID_MAIN_GET_MAP, CReqGetMapMsg, CAnsGetMapMsg);
        CONVERTDOWN1(ID_MAIN_CREATE_GAME, CReqCreateGameMsg, CAnsCreateGameMsg);
        CONVERTDOWN1(ID_MAIN_FIND_PATH, CReqFindPathMsg, CAnsFindPathMsg);
        CONVERTDOWN1(ID_MAIN_SHOOT, CReqShootMsg, CAnsShootMsg);
        
    default: 
        //插入一条警告信息
        CT_WARNING(("convert down no data body matching MsgID=%d MsgType=%d",
            m_stDataHead.shMsgID, m_stDataHead.shMsgType));
        break;
    }
    return 0;
}


